package com.bupt.hotel.hvac.service;

import com.bupt.hotel.hvac.config.HvacConfig;
import com.bupt.hotel.hvac.model.domain.ServiceObject;
import com.bupt.hotel.hvac.model.domain.ServiceRequest;
import com.bupt.hotel.hvac.model.domain.WaitingObject;
import com.bupt.hotel.hvac.model.enums.FanSpeed;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * 调度服务
 * 负责接收空调客户端的请求，并根据"优先级+时间片"调度策略进行调度
 */
@Slf4j
@Service
public class SchedulerService {

    /**
     * 服务队列（线程安全）
     */
    @Getter
    private final List<ServiceObject> serviceQueue = new CopyOnWriteArrayList<>();

    /**
     * 等待队列（线程安全）
     */
    @Getter
    private final List<WaitingObject> waitingQueue = new CopyOnWriteArrayList<>();

    /**
     * 最大服务对象数量
     */
    private final Integer maxServiceObjects;

    /**
     * 等待时长（秒）
     */
    private final Integer waitTime;

    /**
     * 等待计时器（房间ID -> 定时任务）
     */
    private final Map<String, Timer> waitingTimers = new ConcurrentHashMap<>();

    /**
     * 房间移到等待队列的回调
     */
    private Consumer<String> onRoomMovedToWaitingCallback;

    /**
     * 房间开始服务的回调
     */
    private Consumer<String> onRoomMovedToServingCallback;

    public SchedulerService(HvacConfig config) {
        this.maxServiceObjects = config.getMaxServiceObjects();
        this.waitTime = config.getWaitTime();
        log.info("调度服务初始化完成 - 最大服务对象数: {}, 等待时长: {}秒", maxServiceObjects, waitTime);
    }

    /**
     * 设置回调
     */
    public void setCallbacks(Consumer<String> onWaiting, Consumer<String> onServing) {
        this.onRoomMovedToWaitingCallback = onWaiting;
        this.onRoomMovedToServingCallback = onServing;
    }

    /**
     * 处理新的服务请求
     */
    public synchronized Map<String, Object> handleRequest(ServiceRequest request) {
        String roomId = request.getRoomId();
        FanSpeed fanSpeed = request.getFanSpeed();
        BigDecimal targetTemp = request.getTargetTemp();

        Map<String, Object> result = new HashMap<>();

        // 检查该房间是否已在服务队列中
        ServiceObject existingService = serviceQueue.stream()
                .filter(s -> s.getRoomId().equals(roomId))
                .findFirst().orElse(null);

        if (existingService != null) {
            // 如果风速改变，作为新请求处理
            if (existingService.getFanSpeed() != fanSpeed) {
                removeFromServiceQueue(roomId);
                return processNewRequest(request);
            } else {
                // 仅调温，更新目标温度
                existingService.setTargetTemp(targetTemp);
                result.put("granted", true);
                result.put("message", "已更新目标温度");
                result.put("isWaiting", false);
                return result;
            }
        }

        // 检查该房间是否已在等待队列中
        WaitingObject existingWaiting = waitingQueue.stream()
                .filter(w -> w.getRoomId().equals(roomId))
                .findFirst().orElse(null);

        if (existingWaiting != null) {
            // 如果风速改变，重新评估优先级
            if (existingWaiting.getFanSpeed() != fanSpeed) {
                removeFromWaitingQueue(roomId);
                return processNewRequest(request);
            } else {
                // 仅调温，更新目标温度
                existingWaiting.setTargetTemp(targetTemp);
                result.put("granted", false);
                result.put("message", "已更新目标温度，继续等待");
                result.put("isWaiting", true);
                return result;
            }
        }

        // 新请求处理
        return processNewRequest(request);
    }

    /**
     * 处理新请求
     */
    private Map<String, Object> processNewRequest(ServiceRequest request) {
        Map<String, Object> result = new HashMap<>();

        // 1. 当服务对象数小于上限时，直接分配服务对象
        if (serviceQueue.size() < maxServiceObjects) {
            ServiceObject service = createServiceObject(request);
            serviceQueue.add(service);
            result.put("granted", true);
            result.put("message", "已分配服务对象");
            result.put("isWaiting", false);
            log.info("房间 {} 获得服务，当前服务队列长度: {}", request.getRoomId(), serviceQueue.size());
            return result;
        }

        // 2. 当服务对象数达到上限时，启动调度策略
        return applySchedulingStrategy(request);
    }

    /**
     * 应用调度策略
     */
    private Map<String, Object> applySchedulingStrategy(ServiceRequest request) {
        Map<String, Object> result = new HashMap<>();
        int requestPriority = request.getFanSpeed().getPriority();

        // 找出风速低于请求风速的服务对象
        List<ServiceObject> lowerPriorityServices = serviceQueue.stream()
                .filter(s -> s.getFanSpeed().getPriority() < requestPriority)
                .collect(Collectors.toList());

        // 2.1 优先级调度策略
        if (!lowerPriorityServices.isEmpty()) {
            ServiceObject serviceToReplace = selectServiceToReplace(lowerPriorityServices);
            moveToWaitingQueue(serviceToReplace);

            ServiceObject service = createServiceObject(request);
            serviceQueue.add(service);

            result.put("granted", true);
            result.put("message", "优先级调度：已分配服务对象");
            result.put("isWaiting", false);
            log.info("房间 {} 抢占服务，被替换房间: {}", request.getRoomId(), serviceToReplace.getRoomId());
            return result;
        }

        // 找出风速等于请求风速的服务对象
        List<ServiceObject> samePriorityServices = serviceQueue.stream()
                .filter(s -> s.getFanSpeed().getPriority() == requestPriority)
                .collect(Collectors.toList());

        // 2.2 时间片调度策略
        if (!samePriorityServices.isEmpty()) {
            WaitingObject waiting = createWaitingObject(request);
            waitingQueue.add(waiting);
            startWaitingTimer(waiting);

            result.put("granted", false);
            result.put("message", String.format("时间片调度：已加入等待队列，预计等待%d秒", waitTime));
            result.put("isWaiting", true);
            log.info("房间 {} 加入等待队列（时间片调度）", request.getRoomId());
            return result;
        }

        // 2.3 风速低于所有服务对象
        WaitingObject waiting = createWaitingObject(request);
        waitingQueue.add(waiting);

        result.put("granted", false);
        result.put("message", "优先级较低：已加入等待队列");
        result.put("isWaiting", true);
        log.info("房间 {} 加入等待队列（优先级较低）", request.getRoomId());
        return result;
    }

    /**
     * 选择要替换的服务对象
     */
    private ServiceObject selectServiceToReplace(List<ServiceObject> lowerPriorityServices) {
        // 找出风速最低的服务对象
        int minPriority = lowerPriorityServices.stream()
                .mapToInt(s -> s.getFanSpeed().getPriority())
                .min().orElse(0);

        List<ServiceObject> lowestPriorityServices = lowerPriorityServices.stream()
                .filter(s -> s.getFanSpeed().getPriority() == minPriority)
                .collect(Collectors.toList());

        // 如果有多个，选择服务时长最大的
        return lowestPriorityServices.stream()
                .max(Comparator.comparingInt(ServiceObject::getServiceDuration))
                .orElse(lowestPriorityServices.get(0));
    }

    /**
     * 创建服务对象
     */
    private ServiceObject createServiceObject(ServiceRequest request) {
        ServiceObject service = new ServiceObject();
        service.setId(generateServiceId());
        service.setRoomId(request.getRoomId());
        service.setFanSpeed(request.getFanSpeed());
        service.setTargetTemp(request.getTargetTemp());
        service.setCurrentTemp(request.getCurrentTemp());
        service.setServiceStartTime(request.getTimestamp());
        service.setServiceDuration(0);
        service.setPowerConsumption(BigDecimal.ZERO);
        service.setCost(BigDecimal.ZERO);
        return service;
    }

    /**
     * 创建等待对象
     */
    private WaitingObject createWaitingObject(ServiceRequest request) {
        WaitingObject waiting = new WaitingObject();
        waiting.setRoomId(request.getRoomId());
        waiting.setFanSpeed(request.getFanSpeed());
        waiting.setTargetTemp(request.getTargetTemp());
        waiting.setCurrentTemp(request.getCurrentTemp());
        waiting.setWaitStartTime(request.getTimestamp());
        waiting.setWaitDuration(0);
        waiting.setAssignedWaitTime(waitTime);
        return waiting;
    }

    /**
     * 将服务对象移至等待队列
     */
    private void moveToWaitingQueue(ServiceObject service) {
        removeFromServiceQueue(service.getRoomId());

        WaitingObject waiting = new WaitingObject();
        waiting.setRoomId(service.getRoomId());
        waiting.setFanSpeed(service.getFanSpeed());
        waiting.setTargetTemp(service.getTargetTemp());
        waiting.setCurrentTemp(service.getCurrentTemp());
        waiting.setWaitStartTime(System.currentTimeMillis());
        waiting.setWaitDuration(0);
        waiting.setAssignedWaitTime(waitTime);

        waitingQueue.add(waiting);
        startWaitingTimer(waiting);

        // 触发回调
        if (onRoomMovedToWaitingCallback != null) {
            onRoomMovedToWaitingCallback.accept(service.getRoomId());
        }
    }

    /**
     * 启动等待计时器
     */
    private void startWaitingTimer(WaitingObject waiting) {
        String roomId = waiting.getRoomId();
        Timer timer = new Timer();

        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                WaitingObject w = waitingQueue.stream()
                        .filter(obj -> obj.getRoomId().equals(roomId))
                        .findFirst().orElse(null);

                if (w == null) {
                    timer.cancel();
                    waitingTimers.remove(roomId);
                    return;
                }

                w.setWaitDuration(w.getWaitDuration() + 1);

                // 如果等待时长达到分配的等待时长
                if (w.getWaitDuration() >= w.getAssignedWaitTime()) {
                    checkTimeSliceScheduling(w);
                }
            }
        }, 1000, 1000); // 每秒执行一次

        waitingTimers.put(roomId, timer);
    }

    /**
     * 检查时间片调度
     */
    private synchronized void checkTimeSliceScheduling(WaitingObject waiting) {
        // 找出相同风速的服务对象
        List<ServiceObject> samePriorityServices = serviceQueue.stream()
                .filter(s -> s.getFanSpeed() == waiting.getFanSpeed())
                .collect(Collectors.toList());

        if (!samePriorityServices.isEmpty()) {
            // 找出服务时长最大的服务对象
            ServiceObject longestService = samePriorityServices.stream()
                    .max(Comparator.comparingInt(ServiceObject::getServiceDuration))
                    .orElse(null);

            if (longestService != null) {
                // 替换服务对象
                moveToWaitingQueue(longestService);

                // 清除等待计时器
                clearWaitingTimer(waiting.getRoomId());

                // 分配服务对象给等待中的请求
                removeFromWaitingQueue(waiting.getRoomId());

                ServiceObject service = new ServiceObject();
                service.setId(generateServiceId());
                service.setRoomId(waiting.getRoomId());
                service.setFanSpeed(waiting.getFanSpeed());
                service.setTargetTemp(waiting.getTargetTemp());
                service.setCurrentTemp(waiting.getCurrentTemp());
                service.setServiceStartTime(System.currentTimeMillis());
                service.setServiceDuration(0);
                service.setPowerConsumption(BigDecimal.ZERO);
                service.setCost(BigDecimal.ZERO);

                serviceQueue.add(service);

                // 触发回调
                if (onRoomMovedToServingCallback != null) {
                    onRoomMovedToServingCallback.accept(waiting.getRoomId());
                }

                log.info("时间片调度：房间 {} 获得服务，替换房间 {}", waiting.getRoomId(), longestService.getRoomId());
            }
        }
    }

    /**
     * 清除等待计时器
     */
    private void clearWaitingTimer(String roomId) {
        Timer timer = waitingTimers.remove(roomId);
        if (timer != null) {
            timer.cancel();
        }
    }

    /**
     * 释放服务对象（房间达到目标温度或关机）
     */
    public synchronized void releaseService(String roomId) {
        removeFromServiceQueue(roomId);
        processWaitingQueue();
        log.info("房间 {} 释放服务，当前服务队列长度: {}", roomId, serviceQueue.size());
    }

    /**
     * 处理等待队列（有服务对象空闲时）
     */
    private void processWaitingQueue() {
        if (waitingQueue.isEmpty() || serviceQueue.size() >= maxServiceObjects) {
            return;
        }

        // 按优先级和等待时长排序
        List<WaitingObject> sortedWaiting = new ArrayList<>(waitingQueue);
        sortedWaiting.sort((a, b) -> {
            int priorityDiff = b.getFanSpeed().getPriority() - a.getFanSpeed().getPriority();
            if (priorityDiff != 0)
                return priorityDiff;

            // 优先级相同时，比较是否已等待满指定秒数
            boolean aComplete = a.getWaitDuration() >= a.getAssignedWaitTime();
            boolean bComplete = b.getWaitDuration() >= b.getAssignedWaitTime();

            if (aComplete && !bComplete)
                return -1;
            if (!aComplete && bComplete)
                return 1;

            // 都满或都不满时，按等待时长排序
            return b.getWaitDuration() - a.getWaitDuration();
        });

        WaitingObject nextWaiting = sortedWaiting.get(0);

        // 清除等待计时器
        clearWaitingTimer(nextWaiting.getRoomId());

        // 移除等待对象
        removeFromWaitingQueue(nextWaiting.getRoomId());

        // 分配服务对象
        ServiceObject service = new ServiceObject();
        service.setId(generateServiceId());
        service.setRoomId(nextWaiting.getRoomId());
        service.setFanSpeed(nextWaiting.getFanSpeed());
        service.setTargetTemp(nextWaiting.getTargetTemp());
        service.setCurrentTemp(nextWaiting.getCurrentTemp());
        service.setServiceStartTime(System.currentTimeMillis());
        service.setServiceDuration(0);
        service.setPowerConsumption(BigDecimal.ZERO);
        service.setCost(BigDecimal.ZERO);

        serviceQueue.add(service);

        // 触发回调
        if (onRoomMovedToServingCallback != null) {
            onRoomMovedToServingCallback.accept(nextWaiting.getRoomId());
        }

        log.info("等待队列处理：房间 {} 获得服务", nextWaiting.getRoomId());
    }

    /**
     * 更新服务对象的时长和温度
     */
    public void updateServiceDuration(String roomId, Integer duration, BigDecimal powerConsumption,
            BigDecimal cost, BigDecimal currentTemp) {
        serviceQueue.stream()
                .filter(s -> s.getRoomId().equals(roomId))
                .findFirst()
                .ifPresent(s -> {
                    s.setServiceDuration(duration);
                    s.setPowerConsumption(powerConsumption);
                    s.setCost(cost);
                    s.setCurrentTemp(currentTemp);
                });
    }

    /**
     * 更新等待对象的温度
     */
    public void updateWaitingTemp(String roomId, BigDecimal currentTemp) {
        waitingQueue.stream()
                .filter(w -> w.getRoomId().equals(roomId))
                .findFirst()
                .ifPresent(w -> w.setCurrentTemp(currentTemp));
    }

    /**
     * 从服务队列移除
     */
    private void removeFromServiceQueue(String roomId) {
        serviceQueue.removeIf(s -> s.getRoomId().equals(roomId));
    }

    /**
     * 从等待队列移除
     */
    private void removeFromWaitingQueue(String roomId) {
        clearWaitingTimer(roomId);
        waitingQueue.removeIf(w -> w.getRoomId().equals(roomId));
    }

    /**
     * 清空等待队列
     */
    public synchronized List<String> clearAllWaiting() {
        List<String> roomIds = waitingQueue.stream()
                .map(WaitingObject::getRoomId)
                .collect(Collectors.toList());

        // 清除所有等待计时器
        roomIds.forEach(this::clearWaitingTimer);

        // 清空等待队列
        waitingQueue.clear();

        log.info("清空等待队列，共 {} 个房间", roomIds.size());
        return roomIds;
    }

    /**
     * 生成服务对象ID
     */
    private String generateServiceId() {
        return "service_" + System.currentTimeMillis() + "_" + UUID.randomUUID().toString().substring(0, 8);
    }
}
